SIMPLIFIED educational demonstration focusing on the infection mechanism of the XZ Utils backdoor.
This repository contains simplified Python files that clearly demonstrate how the backdoor infects a system and hooks SSH authentication. Perfect for studying the attack mechanism step-by-step.
sshd starts
β
Loads libsystemd-shared.so (for sd_notify)
β
Loads liblzma.so.5.6.0 (for journal compression) β οΈ BACKDOORED
β
Constructor runs: _init_backdoor() [BEFORE main!]
β
Hooks RSA_public_decrypt() in libcrypto.so.3
β
Backdoor is ACTIVE - waiting for magic signature
-
liblzma.py- β THE INFECTION MECHANISM β- Shows the 3-step infection process
- Step 1: Library loads (constructor runs BEFORE main)
- Step 2: Hook installation (dlsym + mprotect + JMP)
- Step 3: Backdoor active (monitoring RSA calls)
- Simple payload handler for magic signature detection
-
libsystemd.py- The dependency bridge- Shows WHY sshd loads liblzma (journal compression)
- Demonstrates the infection trigger
- Clean and focused on the dependency chain
-
libcrypto.py- The hooked function- Shows RSA_public_decrypt() before and after hooking
- Demonstrates signature interception
- Clear comparison: normal vs backdoor authentication
-
sshd.py- Complete demonstration- Ties everything together
- Shows full infection flow
- Tests both normal and backdoor authentication
- Run this to see everything in action
-
infection_flow.py- π¬ Interactive visual demo- Step-by-step animated demonstration
- Shows memory layout and hook installation
- Great for presentations and learning
-
build_process.py- Build-time injection (advanced)- How the backdoor was injected during compilation
- Modified m4 macros and test files
- For deeper study after understanding infection
STEP 1: Library Load
- When
liblzma.soloads, constructor runs automatically - Uses
__attribute__((constructor))- runs BEFORE main() - This is the key: code executes just by loading the library!
__attribute__((constructor))
void _init_backdoor(void) {
// This runs automatically when liblzma.so loads
install_hook();
}STEP 2: Hook Installation
- Find
RSA_public_decrypt()address usingdlsym() - Make memory writable using
mprotect() - Write JMP instruction:
E9 XX XX XX XX - JMP redirects to backdoor handler
void *rsa = dlsym(RTLD_DEFAULT, "RSA_public_decrypt");
mprotect(rsa, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
unsigned char jmp[5] = {0xE9, ...}; // JMP opcode
memcpy(rsa, jmp, 5); // Install hookSTEP 3: Interception
- Every SSH authentication now goes through backdoor
- Check signature for magic bytes:
\x00\x00\x00\x00 - If magic: execute attacker command, return success
- If normal: pass through to real RSA verification
Why did sshd load liblzma?
sshd
ββ calls sd_notify() [Debian/Fedora patch]
ββ loads libsystemd-shared.so
ββ needs XZ compression for journald
ββ loads liblzma.so β οΈ BACKDOOR ACTIVATES HERE
This unexpected dependency chain is what made the attack possible!
python3 sshd.pyBest starting point! Shows the complete infection from start to finish:
- Library loading sequence
- Constructor execution
- Hook installation
- Normal vs backdoor authentication
python3 infection_flow.pyStep-by-step visual walkthrough with animations. Great for understanding the flow!
# The core infection mechanism
python3 liblzma.py
# The dependency bridge
python3 libsystemd.py
# The hooked function
python3 libcrypto.pypython3 build_process.pyHow the backdoor was inserted during compilation (study this last).
- Unexpected Dependency: Debian/Fedora patched OpenSSH to call
sd_notify(), creating sshd β libsystemd link - Legitimate Need: libsystemd uses liblzma for journal compression
- Early Execution: IFUNC resolvers run before
main(), during dynamic linking - Code Reuse: Used existing OpenSSL functions, just intercepted them
- Obfuscation: Payload hidden in "corrupt" test files that appeared legitimate
| Library | Function | Purpose in Attack |
|---|---|---|
| liblzma | crc64_clmul() |
IFUNC resolver installed here |
| liblzma | _backdoor_init() |
Constructor that runs before main() |
| libcrypto | RSA_public_decrypt() |
Target function - hooked |
| libsystemd | sd_notify() |
Creates the dependency link |
| libc | dlsym() |
Find RSA function address |
| libc | mprotect() |
Make code writable for hook |
tests/files/bad-3-corrupt_lzma2.xz
β (extracted during ./configure)
m4/build-to-host.m4
β (generates modified source)
src/liblzma/check/crc64_fast.c
β (compiled with backdoor)
liblzma.so.5.6.0
β (installed to /usr/lib)
BACKDOOR ACTIVE
This demonstrates:
- Supply chain attacks: 2+ years of trust building
- Build system exploitation: Malicious m4 macros
- Dynamic linking attacks: IFUNC resolvers
- Function hooking: Runtime code modification
- Obfuscation techniques: Binary test files
- Responsible disclosure: How Andres Freund's vigilance saved the day
- Debian sid (unstable) - liblzma 5.6.0/5.6.1
- Fedora 40/41 (rawhide) - liblzma 5.6.0/5.6.1
- Arch Linux (briefly) - quickly reverted
- NOT AFFECTED: Stable distributions (caught before release)
Check your system:
# Check XZ version
xz --version
# If 5.6.0 or 5.6.1, check for backdoor
strings /usr/lib/x86_64-linux-gnu/liblzma.so.5 | grep -i "bad-3-corrupt"
# Check if sshd links to liblzma
ldd /usr/sbin/sshd | grep liblzma- CVE-2024-3094: https://nvd.nist.gov/vuln/detail/CVE-2024-3094
- Original Disclosure: https://www.openwall.com/lists/oss-security/2024/03/29/4
- Technical Analysis: https://gist.github.com/thesamesam/223949d5a074ebc3dce9ee78baad9e27
- Andres Freund's Discovery: https://mastodon.social/@AndresFreundTec/112180406142695845
Andres Freund (PostgreSQL developer, Microsoft engineer) discovered this backdoor on March 29, 2024, by noticing a 500ms SSH login delay during routine performance testing. His curiosity and debugging skills with Valgrind prevented a catastrophic supply chain attack.
SIMPLIFIED educational demonstration focusing on the infection mechanism of the XZ Utils backdoor.
This repository contains simplified Python files that clearly demonstrate how the backdoor infects a system and hooks SSH authentication. Perfect for studying the attack mechanism step-by-step.
sshd starts
β
Loads libsystemd-shared.so (for sd_notify)
β
Loads liblzma.so.5.6.0 (for journal compression) β οΈ BACKDOORED
β
Constructor runs: _init_backdoor() [BEFORE main!]
β
Hooks RSA_public_decrypt() in libcrypto.so.3
β
Backdoor is ACTIVE - waiting for magic signature
-
liblzma.py- β THE INFECTION MECHANISM β- Shows the 3-step infection process
- Step 1: Library loads (constructor runs BEFORE main)
- Step 2: Hook installation (dlsym + mprotect + JMP)
- Step 3: Backdoor active (monitoring RSA calls)
- Simple payload handler for magic signature detection
-
libsystemd.py- The dependency bridge- Shows WHY sshd loads liblzma (journal compression)
- Demonstrates the infection trigger
- Clean and focused on the dependency chain
-
libcrypto.py- The hooked function- Shows RSA_public_decrypt() before and after hooking
- Demonstrates signature interception
- Clear comparison: normal vs backdoor authentication
-
sshd.py- Complete demonstration- Ties everything together
- Shows full infection flow
- Tests both normal and backdoor authentication
- Run this to see everything in action
-
infection_flow.py- π¬ Interactive visual demo- Step-by-step animated demonstration
- Shows memory layout and hook installation
- Great for presentations and learning
-
build_process.py- Build-time injection (advanced)- How the backdoor was injected during compilation
- Modified m4 macros and test files
- For deeper study after understanding infection
STEP 1: Library Load
- When
liblzma.soloads, constructor runs automatically - Uses
__attribute__((constructor))- runs BEFORE main() - This is the key: code executes just by loading the library!
__attribute__((constructor))
void _init_backdoor(void) {
// This runs automatically when liblzma.so loads
install_hook();
}STEP 2: Hook Installation
- Find
RSA_public_decrypt()address usingdlsym() - Make memory writable using
mprotect() - Write JMP instruction:
E9 XX XX XX XX - JMP redirects to backdoor handler
void *rsa = dlsym(RTLD_DEFAULT, "RSA_public_decrypt");
mprotect(rsa, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
unsigned char jmp[5] = {0xE9, ...}; // JMP opcode
memcpy(rsa, jmp, 5); // Install hookSTEP 3: Interception
- Every SSH authentication now goes through backdoor
- Check signature for magic bytes:
\x00\x00\x00\x00 - If magic: execute attacker command, return success
- If normal: pass through to real RSA verification
Why did sshd load liblzma?
sshd
ββ calls sd_notify() [Debian/Fedora patch]
ββ loads libsystemd-shared.so
ββ needs XZ compression for journald
ββ loads liblzma.so β οΈ BACKDOOR ACTIVATES HERE
This unexpected dependency chain is what made the attack possible!
python3 sshd.pyBest starting point! Shows the complete infection from start to finish:
- Library loading sequence
- Constructor execution
- Hook installation
- Normal vs backdoor authentication
python3 infection_flow.pyStep-by-step visual walkthrough with animations. Great for understanding the flow!
# The core infection mechanism
python3 liblzma.py
# The dependency bridge
python3 libsystemd.py
# The hooked function
python3 libcrypto.pypython3 build_process.pyHow the backdoor was inserted during compilation (study this last).
1οΈβ£ START HERE - Complete Demo
python3 sshd.pyβ See the complete infection from start to finish
β Shows library loading, hook installation, auth bypass
β Best entry point for understanding the attack
2οΈβ£ Visual Walkthrough
python3 infection_flow.pyβ Interactive step-by-step demonstration
β Animated with memory layout diagrams
β Great for presentations
3οΈβ£ Core Mechanism
python3 liblzma.pyβ THE KEY FILE - shows the 3-step infection
β Constructor execution, hook installation, payload
β Study this to understand how it really works
4οΈβ£ Dependency Chain
python3 libsystemd.pyβ Why does sshd load liblzma?
β The unexpected dependency that enabled the attack
5οΈβ£ Hook Target
python3 libcrypto.pyβ The RSA_public_decrypt() function that gets hooked
β How signatures are intercepted
6οΈβ£ Build-Time Injection (Advanced)
python3 build_process.pyβ How the backdoor was inserted during compilation
β Modified m4 macros and obfuscated test files
- README.md - Complete overview with technical details
- INFECTION_MECHANISM.md - Quick reference guide with summary of the 3-step infection and key technical points table
| Concept | Code Example | Description |
|---|---|---|
| Constructor | __attribute__((constructor)) |
Runs when library loads, BEFORE main() |
| IFUNC | __attribute__((ifunc)) |
Indirect function resolution at runtime |
| dlsym() | dlsym(RTLD_DEFAULT, func) |
Find function address in memory |
| mprotect() | mprotect(addr, size, PROT_WRITE) |
Make code memory writable |
| JMP Hook | E9 XX XX XX XX (opcode) |
x86-64 relative jump instruction |
| Magic Sig | \x00\x00\x00\x00 |
Attacker identification bytes |
STEP 1: Library Load
- liblzma.so loads into sshd process
- Constructor runs BEFORE main()
STEP 2: Hook Installation
- dlsym() finds RSA_public_decrypt()
- mprotect() makes memory writable
- JMP instruction redirects to backdoor
STEP 3: Backdoor Active
- All SSH auth goes through hook
- Magic signature β bypass auth
- Normal signature β real verification
- Understand constructor functions and early execution
- Learn how dynamic linking and IFUNC resolvers work
- See how runtime function hooking is implemented
- Recognize supply chain attack patterns
- Appreciate the importance of performance monitoring
- Unexpected Dependency: Debian/Fedora patched OpenSSH to call
sd_notify(), creating sshd β libsystemd link - Legitimate Need: libsystemd uses liblzma for journal compression
- Early Execution: IFUNC resolvers run before
main(), during dynamic linking - Code Reuse: Used existing OpenSSL functions, just intercepted them
- Obfuscation: Payload hidden in "corrupt" test files that appeared legitimate
| Library | Function | Purpose in Attack |
|---|---|---|
| liblzma | crc64_clmul() |
IFUNC resolver installed here |
| liblzma | _backdoor_init() |
Constructor that runs before main() |
| libcrypto | RSA_public_decrypt() |
Target function - hooked |
| libsystemd | sd_notify() |
Creates the dependency link |
| libc | dlsym() |
Find RSA function address |
| libc | mprotect() |
Make code writable for hook |
tests/files/bad-3-corrupt_lzma2.xz
β (extracted during ./configure)
m4/build-to-host.m4
β (generates modified source)
src/liblzma/check/crc64_fast.c
β (compiled with backdoor)
liblzma.so.5.6.0
β (installed to /usr/lib)
BACKDOOR ACTIVE
This demonstrates:
- Supply chain attacks: 2+ years of trust building
- Build system exploitation: Malicious m4 macros
- Dynamic linking attacks: IFUNC resolvers
- Function hooking: Runtime code modification
- Obfuscation techniques: Binary test files
- Responsible disclosure: How Andres Freund's vigilance saved the day
- Debian sid (unstable) - liblzma 5.6.0/5.6.1
- Fedora 40/41 (rawhide) - liblzma 5.6.0/5.6.1
- Arch Linux (briefly) - quickly reverted
- NOT AFFECTED: Stable distributions (caught before release)
Check your system:
# Check XZ version
xz --version
# If 5.6.0 or 5.6.1, check for backdoor
strings /usr/lib/x86_64-linux-gnu/liblzma.so.5 | grep -i "bad-3-corrupt"
# Check if sshd links to liblzma
ldd /usr/sbin/sshd | grep liblzma- CVE-2024-3094: https://nvd.nist.gov/vuln/detail/CVE-2024-3094
- Original Disclosure: https://www.openwall.com/lists/oss-security/2024/03/29/4
- Technical Analysis: https://gist.github.com/thesamesam/223949d5a074ebc3dce9ee78baad9e27
- Andres Freund's Discovery: https://mastodon.social/@AndresFreundTec/112180406142695845
- text wolves in the repository
Andres Freund (PostgreSQL developer, Microsoft engineer) discovered this backdoor on March 29, 2024, by noticing a 500ms SSH login delay during routine performance testing. His curiosity and debugging skills with Valgrind prevented a catastrophic supply chain attack.